package com.reminis.exceldemo.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.function.Function;

import com.reminis.exceldemo.annotation.ExcelColumn;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * Excel工具类
 */
public class ExcelUtils {

    public final static Logger log = LoggerFactory.getLogger(ExcelUtils.class);

    public final static String EXCEL2003 = "xls";
    public final static String EXCEL2007 = "xlsx";

    /**
     * 校验数据列表中金额字段的小数位数。
     * 确保至少存在一个金额的小数位数为3或4位。
     *
     * @param dataList 数据列表
     * @param dataType 数据类型描述（例如，"下单数据"或"发货数据"）
     * @throws IllegalArgumentException 如果没有任何金额的小数位数为3或4位
     */
    public static void validateAmountDecimalPlaces(List<com.reminis.exceldemo.entity.TextInputDataDto> dataList, String dataType) {
        if (CollectionUtils.isEmpty(dataList)) {
            return; // 空列表无需校验
        }

        boolean foundRequiredScale = false;
        for (com.reminis.exceldemo.entity.TextInputDataDto dto : dataList) {
            String amountStr = dto.getAmount();

            // 跳过空值或非数字
            if (StringUtils.isBlank(amountStr)) {
                continue;
            }

            try {
                BigDecimal amount = new BigDecimal(amountStr);
                int scale = amount.scale();
                // 检查小数位数是否为3或4
                if (scale == 3 || scale == 4) {
                    foundRequiredScale = true;
                    break; // 找到一个符合条件的即可退出
                }
            } catch (NumberFormatException e) {
                // 忽略无法解析为数字的金额，因为基础校验会处理它们
                log.warn("无法将金额 '{}' 解析为数字，在小数位数校验中跳过", amountStr);
            }
        }

        // 如果遍历完所有数据都没有找到符合条件的金额
        if (!foundRequiredScale) {
            String errorMessage = String.format("%s：写入数据格式在Excel中没有设置格式为常规 (未找到小数位为3或4的金额)", dataType);
            log.error(errorMessage);
            throw new IllegalArgumentException(errorMessage);
        } else {
             log.info("{} 金额小数位数校验通过 (至少存在一个金额的小数位数为3或4位)", dataType);
        }
    }

    public static <T> List<T> readExcel(String path, Class<T> cls, MultipartFile file){
        //  System.out.println("进入readExcel");
        if (file.isEmpty()) {
            log.error("上传文件不能为空");
        }

        String fileName = file.getOriginalFilename();
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            log.error("上传文件格式不正确");
        }
        List<T> dataList = new ArrayList<>();
        Workbook workbook = null;
        try {
            InputStream is = file.getInputStream();
            if (fileName.endsWith(EXCEL2007)) {
//                FileInputStream is = new FileInputStream(new File(path));
                workbook = new XSSFWorkbook(is);
            }
            if (fileName.endsWith(EXCEL2003)) {
//                FileInputStream is = new FileInputStream(new File(path));
                workbook = new HSSFWorkbook(is);
            }
            if (workbook != null) {
                //类映射  注解 value-->bean columns
                Map<String, List<Field>> classMap = new HashMap<>();
                List<Field> fields = Stream.of(cls.getDeclaredFields()).collect(Collectors.toList());
                fields.forEach(
                        field -> {
                            ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
                            if (annotation != null) {
                                String value = annotation.value();
                                if (StringUtils.isBlank(value)) {
                                    return;//return起到的作用和continue是相同的 语法
                                }
                                if (!classMap.containsKey(value)) {
                                    classMap.put(value, new ArrayList<>());
                                }
                                field.setAccessible(true);
                                classMap.get(value).add(field);
                            }
                        }
                );
                //后面使用它来 执行计算公式
                // FormulaEvaluator formulaEvaluator = new XSSFFormulaEvaluator((XSSFWorkbook) workbook);
                FormulaEvaluator formulaEvaluator = workbook.getCreationHelper().createFormulaEvaluator();
                //索引-->columns
                Map<Integer, List<Field>> reflectionMap = new HashMap<>(16);
                //默认读取第一个sheet
                Sheet sheet = workbook.getSheetAt(0);
                //索引-->columns
                boolean firstRow = true;

                for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
                    Row row = sheet.getRow(i);
                    //首行  提取注解
                    if (firstRow) {
                        for (int j = row.getFirstCellNum(); j<= row.getLastCellNum(); j++) {
                            Cell cell = row.getCell(j);
                            String cellValue = getCellValue(cell);
                            // System.out.println("打印Excel上传第一行列名字段："+cellValue);
                            if(cellValue.equals("Raw Material Catagory")){
                                cellValue ="大类";//如果表头列名为"Raw Material Catagory"，重新将该列命名为"大类"
                            }
                            if (classMap.containsKey(cellValue)) {
                                // System.out.println("打印存入的字段："+cellValue);
                                reflectionMap.put(j, classMap.get(cellValue));
                            }
                        }
                        firstRow = false;
                    }
                    else {//读取第二行及以下的数据
                        // System.out.println("进入读取非首行数据else");
                        //忽略空白行
                        if (row == null) {
                            continue;
                        }
                        try {
                            // System.out.println("进入读取非首行数据try");
                            T t = cls.newInstance();
                            //判断是否为空白行
                            boolean allBlank = true;
                            // System.out.println("打印获取每行的列数"+row.getFirstCellNum());
                            for (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {
                                // System.out.println("进入读取非首行数据for"+i);
                                if (reflectionMap.containsKey(j)) {
                                    //    System.out.println("进入读取非首行数据if,获取每列数据"+j);
                                    Cell cell = row.getCell(j);
                                    //测试验证读取小数数据正常
                                   /*  String cellstring = cell.toString();
                                       if(cellstring.equals("3044.4")){
                                          System.out.println("打印3044.4对应转换值"+getCellValue(cell));
                                        }*/
                                    //getCellValue解析单元格数据
                                    String cellValue = getCellValue(cell);
                                    //  System.out.println("进入读取非首行数据if,获取每列数据cellValue:"+cellValue);
                                    if (cellValue.contains( "WW-")){//截取材料名称WW-
                                        String key = "WW-";
                                        int indexOf = cellValue.indexOf(key);
                                        if (indexOf != -1) {
                                            cellValue = key+cellValue.substring(indexOf+key.length()).split(" ")[0];
                                            //   System.out.println("打印截取后的材料名称:"+cellValue);
                                        }
                                    }
                                    //判断单元格是否为公式，执行计算公式
                                    if (cell == null) {
                                        cellValue = "";
                                        // }else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA){
                                    }else if (cell.getCellType() == CellType.FORMULA){
                                        // System.out.println("进入判断为公式类型");
                                        String cellFormula = cell.getCellFormula();
                                        // 评估单元格的公式，并获取结果
                                        CellValue evaluate = formulaEvaluator.evaluate(cell);
                                        //System.out.println("公式：" + cellFormula);
                                        BigDecimal bd = new BigDecimal(evaluate.getNumberValue());
                                        bd = bd.setScale(4, RoundingMode.HALF_UP); // 设置小数点后四位，并进行四舍五入
                                        // System.out.println("计算公式前的值：" + bd);

                                        DataFormatter dataFormatter = new DataFormatter();
                                        // 使用 dataFormatter 格式化公式结果
                                        String formattedValue = dataFormatter.formatCellValue(cell, formulaEvaluator);
                                        // 去掉公式中的逗号
                                        formattedValue = formattedValue.replace(",", "");

                                        cellValue = bd.toString();

                                    }
                                    if (cellValue.contains( "PD")){//截取采购单号PD24101032示例，PD24101032()
                                        String key = "(";
                                        int indexOf = cellValue.indexOf(key);
                                        if (indexOf != -1) {
                                            //截取采购单号PD24101032示例，PD24101032(N41663.N42326.N42431.N42436-N42439.N42442)
                                            cellValue = cellValue.substring(0,indexOf);
                                            //   System.out.println("打印截取后的采购单号:"+cellValue);
                                        }
                                    }
                                    if (StringUtils.isNotBlank(cellValue)) {
                                        allBlank = false;
                                    }

                                    List<Field> fieldList = reflectionMap.get(j);
                                    //替代forEach循环赋值
                                    for (int k = 0; k <fieldList.size() ; k++) {
                                        Field field = fieldList.get(k);
                                        // System.out.println("打印获取每列数据field:"+field.getName()+",数据类型："+field.getType());

                                        field.set(t,cellValue);
                                        // System.out.println("field.set结束,打印获取每列数据field:"+field.getName()+",数据类型："+field.getType()+",数据值："+cellValue);
                                    }
                                   /* fieldList.forEach(
                                            x -> {
                                                try {
                                                    handleField(t, cellValue, x);
                                                } catch (Exception e) {
                                                    log.error(String.format("reflect field:%s value:%s exception!", x.getName(), cellValue), e);
                                                }
                                            }
                                    );*/
                                }
                            }
                            if (!allBlank) {
                                dataList.add(t);
                            } else {//忽略空白行警告信息，不打印
                                //log.warn(String.format("row:%s is blank ignore!", i));
                            }
                        } catch (Exception e) {
                            log.error(String.format("parse row:%s exception!", i), e);
                        }
                    }
                }


            }
        } catch (Exception e) {
            log.error(String.format("parse excel exception!"), e);
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (Exception e) {
                    log.error(String.format("parse excel exception!"), e);
                }
            }
        }
        // System.out.println("结束readExcel:"+dataList);
        return dataList;
    }

    /**
     * 读取Excel文件内容（处理两个sheet页数据）
     * @param path 文件路径（本方法未使用）
     * @param cls 目标类型
     * @param file 上传的文件对象
     * @return 返回解析后的数据列表
     * @param <T> 泛型类型
     */
    

    

    public static <T> void handleField(T t, String value, Field field) throws Exception {
        Class<?> type = field.getType();
        if (type == void.class || StringUtils.isBlank(value)) {
            return;
        }
        if (type == Object.class) {
            field.set(t, value);
        } else if (type.getSuperclass() == null || type.getSuperclass() == Number.class) {
            if (type == int.class || type == Integer.class) {
                field.set(t, NumberUtils.toInt(value));
            } else if (type == long.class || type == Long.class) {
                field.set(t, NumberUtils.toLong(value));
            } else if (type == byte.class || type == Byte.class) {
                field.set(t, NumberUtils.toByte(value));
            } else if (type == short.class || type == Short.class) {
                field.set(t, NumberUtils.toShort(value));
            } else if (type == double.class || type == Double.class) {
                field.set(t, NumberUtils.toDouble(value));
            } else if (type == float.class || type == Float.class) {
                field.set(t, NumberUtils.toFloat(value));
            } else if (type == char.class || type == Character.class) {
                field.set(t, CharUtils.toChar(value));
            } else if (type == boolean.class) {
                field.set(t, BooleanUtils.toBoolean(value));
            } else if (type == BigDecimal.class) {
                field.set(t, new BigDecimal(value));
            }
        } else if (type == Boolean.class) {
            field.set(t, BooleanUtils.toBoolean(value));
        } else if (type == Date.class) {
            field.set(t, value);
        } else if (type == String.class) {
            field.set(t, value);
        } else if (type == LocalDateTime.class) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime dt = LocalDateTime.parse(value, df);
            field.set(t, dt);
        } else {
            Constructor<?> constructor = type.getConstructor(String.class);
            field.set(t, constructor.newInstance(value));
        }
    }

    public static String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }
        if (cell.getCellType() == CellType.NUMERIC) {//判断数据类型为数字类型
            if (DateUtil.isCellDateFormatted(cell)) {//判断为日期类型
                Date dateCellValue = cell.getDateCellValue();
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");//格式日期类型，参考Excel中类型的格式
                return simpleDateFormat.format(dateCellValue);
            } else {//判断为非日期类型的数字，转化为小数类型的字符串
                Double d = cell.getNumericCellValue();
                DecimalFormat df = new DecimalFormat("#.####");
                String value = df.format(d);
                return value;
            }
        } else if (cell.getCellType() == CellType.STRING) {
            return StringUtils.trimToEmpty(cell.getStringCellValue());
        } else if (cell.getCellType() == CellType.BLANK) {
            return "";
        } else if (cell.getCellType() == CellType.BOOLEAN) {
            return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellType() == CellType.ERROR) {
            return "ERROR";
        } else {
            return cell.toString().trim();
        }
    }

    public static <T> void writeExcel(HttpServletRequest request, HttpServletResponse response,String fileName, List<T> dataList, Class<T> cls) {
        if (CollectionUtils.isEmpty(dataList)) {
            log.warn("数据为空，没有数据可以写入到Excel.");
            return;
        }

        Field[] fields = cls.getDeclaredFields();
        List<Field> fieldList = Arrays.stream(fields)
                .filter(field -> {
                    ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
                    if (annotation != null && annotation.col() > 0) {
                        field.setAccessible(true);
                        return true;
                    }
                    return false;
                })
                .sorted(Comparator.comparing(field -> {
                    int col = 0;
                    ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
                    if (annotation != null) {
                        col = annotation.col();
                    }
                    return col;
                }))
                .collect(Collectors.toList());

        Workbook wb = new XSSFWorkbook();
        Sheet sheet = wb.createSheet("Sheet1");

        AtomicInteger ai = new AtomicInteger();
        {
            Row row = sheet.createRow(ai.getAndIncrement());
            AtomicInteger aj = new AtomicInteger();
            fieldList.forEach(field -> {
                ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
                String columnName = "";
                if (annotation != null) {
                    columnName = annotation.value();
                }
                Cell cell = row.createCell(aj.getAndIncrement());

                CellStyle  cellStyle = wb.createCellStyle();
                cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
                cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                cellStyle.setAlignment(HorizontalAlignment.CENTER);

               /* Font font = wb.createFont();
                font.setBold(true); // 设置字体加粗
                cellStyle.setFont(font);*/

                cell.setCellStyle(cellStyle);
                cell.setCellValue(columnName);
            });
        }

        if (CollectionUtils.isNotEmpty(dataList)) {
            for (int i = 0; i < dataList.size(); i++) {
                int rowIndex = i + 1;
                Row contentRow = sheet.createRow(rowIndex); // 修改这里
                //新增设置列宽,设置列宽为5000
                sheet.setColumnWidth(i, 3000);

                T t = dataList.get(i);
                AtomicInteger aj = new AtomicInteger();
                fieldList.forEach(field -> {
                    Class<?> type = field.getType();
                    Object value = "";
                    try {
                        value = field.get(t);
                    } catch (Exception e) {
                        log.error("Failed to get value from field: {}", field.getName(), e);
                    }
                    Cell cell = contentRow.createCell(aj.getAndIncrement());
                    //新增居中样式
                    CellStyle  cellStyle2 = wb.createCellStyle();
                    cellStyle2.setAlignment(HorizontalAlignment.CENTER);
                    cell.setCellStyle(cellStyle2);
                    //新增居中样式 end


                    // 新增判断'大类'或者'中类'没有内容时，设置输出的Excel当前列背景颜色为黄色
                    ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
                    if (annotation != null && (annotation.value().equals("大类") || annotation.value().equals("中类")) && (value == null || StringUtils.isBlank(value.toString()))) {
                        cellStyle2.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
                        cellStyle2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                    }

                    if (value != null) {
                        // System.out.println("打印type类型："+type);
                        if (type == Date.class) {//要先设置样式，然后再填入值。。。。。。。。。。。。才能生效
                            CellStyle cellStyle = wb.createCellStyle();
                            //  cellStyle.setDataFormat(wb.createDataFormat().getFormat("yyyy/M/d"));//设置日期格式的单元格
                            cellStyle.setDataFormat(wb.createDataFormat().getFormat("yyyy-M-d"));//设置日期格式的单元格
                            cell.setCellStyle(cellStyle);

                            // SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
                            // value = sdf.format((Date) value);
                            // cell.setCellValue((String) value);
                            cell.setCellValue((Date) value);

                            //System.out.println("打印下载的日期格式1："+value);
                        } else if (type == LocalDateTime.class) {
                            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                            cell.setCellValue(df.format((LocalDateTime) value));
                            // System.out.println("打印下载的日期格式2："+value);
                        } else if (type == BigDecimal.class ) {//判断类型为数字类型的话，设置单元格为可以计算的格式
                            // System.out.println("打印BigDecimal类型的值：" + value);
                            //builder.setCellStyle(cellStyle);
                           
                            // 创建一个数据格式对象，设置数据格式为"#,0.00"，用于格式化数字
                            CellStyle cellStyle = wb.createCellStyle();
                            // cellStyle.setDataFormat(dataFormat.getFormat("#,#0"));

                            // cellStyle.setDataFormat(dataFormat.getFormat("#,##0.00"));//保留两位小数点
                            // 设置单元格样式为数字格式
                            //  cell.setCellStyle(cellStyle);
                            // cell.setCellValue(((BigDecimal) value).doubleValue());

                            // 如果是BigDecimal,已数字格式输出, 并且设置单元格为可以计算的格式
                            cell.setCellValue(((BigDecimal) value).doubleValue());
                            cellStyle.setDataFormat(wb.createDataFormat().getFormat("0"));
                        }else if (type == Double.class ) {//判断类型为数字类型的话，设置单元格为可以计算的格式
                            // System.out.println("打印Double类型的值：" + value);
                            //builder.setCellStyle(cellStyle);
                            
                            // 创建一个数据格式对象，设置数据格式为"#,0.00"，用于格式化数字
                            CellStyle cellStyle = wb.createCellStyle();
                            // cellStyle.setDataFormat(dataFormat.getFormat("#,##0.0000"));//保留四位小数点
                            // 如果是Double,已数字格式输出, 并且设置单元格为可以计算的格式
                            cell.setCellValue(((Double) value));
                            cellStyle.setDataFormat(wb.createDataFormat().getFormat("0"));
                        }  else {
                            cell.setCellValue(value.toString());

                        }

                    }
                });
            }
        }

        wb.getSheet("Sheet1").createFreezePane(0, 1, 0, 1);
        //下载的文件名称命名为fileName,方法新增传入文件名称，在具体调用的实现类中定义传入
        buildExcelDocument(fileName +  ".xlsx", wb, response);
    }



    public static void buildExcelDocument(String fileName, Workbook wb, HttpServletResponse response) {
        try {
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
            response.flushBuffer();
            ServletOutputStream outputStream = response.getOutputStream();
            wb.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void buildExcelFile(String path, Workbook wb) {
        File file = new File(path);
        if (file.exists()) {
            file.delete();
        }
        try {
            wb.write(new FileOutputStream(file));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取Excel第一个Sheet (下单数据)
     * 假设:
     * - Sheet索引 0 包含订单数据.
     * - 表头在第一行 (跳过).
     * - 列映射: 中类 (索引 0), 下单数量 (索引 1), 下单金额 (索引 2).
     *
     * @param file 代表Excel文件的MultipartFile对象.
     * @return 包含中类、下单数量、下单金额的Yeji对象列表.
     * @throws IOException 如果读取文件时发生I/O错误.
     * @throws RuntimeException 如果文件格式不正确或Sheet缺失/为空.
     */
    public static List<com.reminis.exceldemo.entity.Yeji> readOrderDataFromSheet1(MultipartFile file) throws IOException {
        log.info("从文件 {} 的 Sheet 1 读取订单数据", file.getOriginalFilename());
        return readSpecificSheet(file, 0, true); // Sheet 索引 0, isOrderSheet = true
    }

    /**
     * 读取Excel第二个Sheet (发货数据)
     * 假设:
     * - Sheet索引 1 包含发货数据.
     * - 表头在第一行 (跳过).
     * - 列映射: 中类 (索引 0), 发货数量 (索引 1), 发货金额 (索引 2).
     *
     * @param file 代表Excel文件的MultipartFile对象.
     * @return 包含中类、发货数量、发货金额的Yeji对象列表.
     * @throws IOException 如果读取文件时发生I/O错误.
     * @throws RuntimeException 如果文件格式不正确或Sheet缺失/为空.
     */
    public static List<com.reminis.exceldemo.entity.Yeji> readShipmentDataFromSheet2(MultipartFile file) throws IOException {
        log.info("从文件 {} 的 Sheet 2 读取发货数据", file.getOriginalFilename());
        return readSpecificSheet(file, 1, false); // Sheet 索引 1, isOrderSheet = false
    }

    /**
     * 读取指定Sheet并直接映射列的辅助方法.
     *
     * @param file         MultipartFile 对象
     * @param sheetIndex   要读取的Sheet的0基索引
     * @param isOrderSheet 如果读取订单数据(Sheet 1)则为True, 如果读取发货数据(Sheet 2)则为False
     * @return Yeji 对象列表
     * @throws IOException 如果发生 I/O 错误
     * @throws RuntimeException 各种处理错误
     */
    private static List<com.reminis.exceldemo.entity.Yeji> readSpecificSheet(MultipartFile file, int sheetIndex, boolean isOrderSheet) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传的文件不能为空.");
        }
        String fileName = file.getOriginalFilename();
        log.debug("处理文件: {}, Sheet索引: {}, 是否订单Sheet: {}", fileName, sheetIndex, isOrderSheet);

        List<com.reminis.exceldemo.entity.Yeji> dataList = new ArrayList<>();
        Workbook workbook = null;
        InputStream is = file.getInputStream();

        try {
            if (fileName.endsWith(EXCEL2007)) {
                workbook = new XSSFWorkbook(is);
            } else if (fileName.endsWith(EXCEL2003)) {
                workbook = new HSSFWorkbook(is);
            } else {
                throw new IllegalArgumentException("无效的文件格式。仅支持 .xls 和 .xlsx。.");
            }

            if (workbook.getNumberOfSheets() <= sheetIndex) {
                 throw new RuntimeException("文件不包含索引为 " + sheetIndex + " 的Sheet (0基索引). 文件: " + fileName);
            }

            Sheet sheet = workbook.getSheetAt(sheetIndex);
            if (sheet == null || sheet.getLastRowNum() < 1) { // 检查Sheet是否存在且至少包含一个数据行（除表头外）
                 log.warn("文件 {} 中索引 {} 处的Sheet为空或缺失", sheetIndex, fileName);
                 // 根据需求，也许返回空列表而不是抛出异常？
                 // 目前，如果Sheet为空/缺失，则返回空列表。
                 return dataList;
                 // 或者抛出异常: throw new RuntimeException("文件 " + fileName + " 中索引 " + sheetIndex + " 处的Sheet为空或缺失");
            }

            int firstDataRow = 1; // 假设表头在第0行，数据从第1行开始

            for (int i = firstDataRow; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    log.warn("跳过Sheet {} 中索引 {} 处的空行", sheetIndex, i);
                    continue; // 跳过空行
                }

                try {
                    // --- 关键假设: 列索引 ---
                    // 中类: A列 (索引 0)
                    // 数量: B列 (索引 1)
                    // 金额: C列 (索引 2)
                    // 如果Excel布局不同，请调整这些索引!
                    // --- --- --- --- --- --- --- ---

                    String zhonglei = getCellValue(row.getCell(0)); // 从A列获取中类
                    if (StringUtils.isBlank(zhonglei)) {
                         log.warn("因'中类'为空，跳过Sheet {} 中的第 {} 行", sheetIndex, i);
                         continue; // 跳过中类为空的行
                    }
                     if ("总计".equals(zhonglei.trim())) {
                         log.debug("跳过Sheet {} 中索引 {} 处的'总计'行", sheetIndex, i);
                         continue; // 根据第一列的值跳过总计行
                    }


                    com.reminis.exceldemo.entity.Yeji yeji = new com.reminis.exceldemo.entity.Yeji();
                    yeji.set中类(zhonglei.trim());

                    String quantityStr = getCellValue(row.getCell(1)); // 从B列获取数量字符串
                    String amountStr = getCellValue(row.getCell(2)); // 从C列获取金额字符串

                    if (isOrderSheet) {
                        // 直接传递原始字符串值
                        yeji.set下单数量(quantityStr);
                        yeji.set下单金额(amountStr);
                    } else {
                         // 直接传递原始字符串值
                        yeji.set发货数量(quantityStr);
                        yeji.set发货金额(amountStr);
                    }

                    dataList.add(yeji);
                    log.trace("从第 {} 行添加Yeji记录: {}", i, yeji);

                } catch (Exception e) {
                    log.error("处理文件 {} 中Sheet {} 的第 {} 行时出错", fileName, sheetIndex, i, e);
                    // 可选地，重新抛出异常或收集错误，而不是仅仅记录日志
                    throw new RuntimeException("处理Sheet " + (sheetIndex + 1) + " 的第 " + (i + 1) + " 行时出错. 详情: " + e.getMessage(), e);
                }
            }
            log.info("成功从文件 {} 的Sheet {} 读取 {} 条数据记录", fileName, sheetIndex, dataList.size());

        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    log.error("关闭文件 {} 的Workbook时出错", fileName, e);
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    log.error("关闭文件 {} 的输入流时出错", fileName, e);
                }
            }
        }

        return dataList;
    }

    /**
     * 从指定Sheet中读取"总计"行的指定列的金额值.
     *
     * @param file             MultipartFile对象
     * @param sheetIndex       要读取的Sheet的0基索引
     * @param amountColumnIndex 金额所在的列的0基索引 (例如 C列 是 2)
     * @return BigDecimal 类型的总计金额
     * @throws IOException      如果发生 I/O 错误
     * @throws RuntimeException 如果找不到"总计"行, 或金额无法解析
     */
    public static BigDecimal readTotalAmountFromSheet(MultipartFile file, int sheetIndex, int amountColumnIndex) throws IOException {
        log.debug("从文件 {} 的 Sheet {} 读取第 {} 列的总计金额", file.getOriginalFilename(), sheetIndex, amountColumnIndex);
        Workbook workbook = null;
        InputStream is = file.getInputStream();
        String fileName = file.getOriginalFilename();
        BigDecimal totalAmount = null;

        try {
            // --- 打开工作簿 ---
            if (fileName.endsWith(EXCEL2007)) {
                workbook = new XSSFWorkbook(is);
            } else if (fileName.endsWith(EXCEL2003)) {
                workbook = new HSSFWorkbook(is);
            } else {
                throw new IllegalArgumentException("无效的文件格式。仅支持 .xls 和 .xlsx。");
            }

            // --- 获取Sheet ---
            if (workbook.getNumberOfSheets() <= sheetIndex) {
                throw new RuntimeException("文件不包含索引为 " + sheetIndex + " 的Sheet. 文件: " + fileName);
            }
            Sheet sheet = workbook.getSheetAt(sheetIndex);
            if (sheet == null) {
                 throw new RuntimeException("文件 " + fileName + " 中索引 " + sheetIndex + " 处的Sheet为空或缺失");
            }

            // --- 查找"总计"行并读取金额 ---
            boolean totalRowFound = false;
            for (int i = 0; i <= sheet.getLastRowNum(); i++) { // 从第一行开始查找
                Row row = sheet.getRow(i);
                if (row == null) continue;

                Cell firstCell = row.getCell(0); // 获取第一列（中类列）
                if (firstCell != null && "总计".equals(getCellValue(firstCell).trim())) {
                    totalRowFound = true;
                    log.debug("在Sheet {} 的第 {} 行找到 '总计' 行", sheetIndex, i + 1);
                    Cell amountCell = row.getCell(amountColumnIndex); // 获取金额列
                    // String amountStr = getCellValue(amountCell); // 不再直接获取字符串

                    if (amountCell == null) { // 检查金额单元格是否存在
                         throw new RuntimeException("Sheet " + (sheetIndex + 1) + " 的 '总计' 行第 " + (amountColumnIndex + 1) + " 列（金额）单元格不存在或为空.");
                    }

                    try {
                         // --- 新增：处理不同单元格类型，特别是公式 ---
                         if (amountCell.getCellType() == CellType.FORMULA) {
                             log.debug("金额单元格是公式，进行求值...");
                             FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
                             // 强制重新计算所有公式单元格的值，以防依赖未计算的单元格
                             // evaluator.evaluateAll(); 
                             // 或者只评估当前单元格
                             CellValue cellValue = evaluator.evaluate(amountCell);
                             // 使用 getNumberValue() 获取计算结果 (double)
                             totalAmount = BigDecimal.valueOf(cellValue.getNumberValue()); 
                             log.info("公式求值结果: {}", totalAmount);
                         } else if (amountCell.getCellType() == CellType.NUMERIC) {
                             log.debug("金额单元格是数值.");
                             // 直接获取数值 (double)
                             totalAmount = BigDecimal.valueOf(amountCell.getNumericCellValue());
                         } else if (amountCell.getCellType() == CellType.STRING) {
                             log.debug("金额单元格是字符串，尝试解析...");
                             String amountStr = amountCell.getStringCellValue();
                             if (StringUtils.isBlank(amountStr)) {
                                 throw new RuntimeException("Sheet " + (sheetIndex + 1) + " 的 '总计' 行第 " + (amountColumnIndex + 1) + " 列（金额）为空字符串.");
                             }
                             amountStr = amountStr.replace(",", ""); // 处理可能的逗号
                             totalAmount = new BigDecimal(amountStr); // 尝试解析字符串
                         } else if (amountCell.getCellType() == CellType.BLANK) {
                             // 如果允许空白单元格表示0，则取消注释下一行
                             // totalAmount = BigDecimal.ZERO;
                             // log.warn("Sheet {} 的 '总计' 行第 {} 列（金额）为空白单元格，计为0.", sheetIndex + 1, amountColumnIndex + 1);
                             // 如果不允许，则抛出错误
                             throw new RuntimeException("Sheet " + (sheetIndex + 1) + " 的 '总计' 行第 " + (amountColumnIndex + 1) + " 列（金额）为空白单元格.");
                         } else {
                             // 其他类型，如 ERROR, BOOLEAN - 视为错误
                             throw new RuntimeException("Sheet " + (sheetIndex + 1) + " 的 '总计' 行第 " + (amountColumnIndex + 1) + " 列（金额）的单元格类型 (" + amountCell.getCellType() + ") 不支持.");
                         }
                         log.info("从文件 {} 的Sheet {} 的 '总计' 行成功读取并计算/解析到金额: {}", fileName, sheetIndex, totalAmount);

                    // } catch (NumberFormatException e) { // BigDecimal构造器或valueOf可能抛出此异常
                    //      throw new RuntimeException("处理 Sheet " + (sheetIndex + 1) + " 的 '总计' 行第 " + (amountColumnIndex + 1) + " 列（金额）时出错: " + e.getMessage(), e);
                    } catch (Exception e) { // 捕获更广泛的异常，包括公式求值错误等
                         throw new RuntimeException("处理 Sheet " + (sheetIndex + 1) + " 的 '总计' 行第 " + (amountColumnIndex + 1) + " 列（金额）时出错: " + e.getMessage(), e);
                    }
                    break; // 找到总计行并处理完金额后停止遍历
                }
            }

            if (!totalRowFound) {
                 throw new RuntimeException("在 Sheet " + (sheetIndex + 1) + " 中未找到 '总计' 行.");
            }

        } finally {
            // --- 关闭资源 ---
            if (workbook != null) {
                try { workbook.close(); } catch (IOException e) { log.error("关闭文件 {} 的Workbook时出错", fileName, e); }
            }
            if (is != null) {
                try { is.close(); } catch (IOException e) { log.error("关闭文件 {} 的输入流时出错", fileName, e); }
            }
        }

        // 如果 totalAmount 仍然是 null (理论上如果找到了总计行且没抛异常就不会)，也抛出错误
        if (totalAmount == null) {
             throw new RuntimeException("无法从 Sheet " + (sheetIndex + 1) + " 的 '总计' 行获取有效的金额.");
        }

        return totalAmount;
    }

    /**
     * 查找字符串列表中忽略大小写的重复项。
     *
     * @param strings 要检查的字符串列表。
     * @return 包含所有重复项（保留原始大小写）的列表。如果无重复项，则返回空列表。
     */
    public static List<String> findCaseInsensitiveDuplicates(List<String> strings) {
        if (strings == null || strings.size() < 2) {
            return new ArrayList<>(); // No duplicates possible
        }

        // Map to store lowercase string to its original case occurrences
        Map<String, List<String>> lowercaseMap = new HashMap<>();

        for (String originalString : strings) {
            if(originalString == null) continue; // Skip nulls if any
            String lowercaseString = originalString.toLowerCase();
            lowercaseMap.computeIfAbsent(lowercaseString, k -> new ArrayList<>()).add(originalString);
        }

        // Collect duplicates (where list size > 1)
        List<String> duplicates = new ArrayList<>();
        for (List<String> originalStrings : lowercaseMap.values()) {
            if (originalStrings.size() > 1) {
                // Add all occurrences of the duplicate string
                duplicates.addAll(originalStrings); 
            }
        }
        
        // Optionally, return only unique duplicate values (e.g., if "Apple" and "apple" are duplicates, return just one)
        // If you need all occurrences (like ["Apple", "apple"]), the current `duplicates` list is correct.
        // If you need just the unique keys that were duplicates (like ["apple"]), you'd collect keys where list size > 1.
        // If you need one representative original string for each duplicate key (like ["Apple"]), you'd take the first element.
        // The current implementation returns ALL original strings that had a case-insensitive duplicate.

        return duplicates;
    }
}
